package cleandata

import (
	"gitee.com/hexug/kube-sync/conf/rules"
	appsv1 "k8s.io/api/apps/v1"
	batchv1 "k8s.io/api/batch/v1"
	batchv1beta1 "k8s.io/api/batch/v1beta1"
	corev1 "k8s.io/api/core/v1"
	rbacv1 "k8s.io/api/rbac/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/json"
	"strings"
)

// WithGVK 为map添加GVK信息
func WithGVK(m map[string]any, obj runtime.Object) map[string]any {
	gvks := obj.GetObjectKind().GroupVersionKind()
	// 某些typed对象可能未携带GVK，这里兜底
	if gvks.Empty() {
		switch obj.(type) {
		case *appsv1.Deployment:
			gvks = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}
		case *appsv1.DaemonSet:
			gvks = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "DaemonSet"}
		case *appsv1.StatefulSet:
			gvks = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "StatefulSet"}
		case *batchv1.Job:
			gvks = schema.GroupVersionKind{Group: "batch", Version: "v1", Kind: "Job"}
		case *batchv1.CronJob:
			gvks = schema.GroupVersionKind{Group: "batch", Version: "v1", Kind: "CronJob"}
		case *batchv1beta1.CronJob:
			gvks = schema.GroupVersionKind{Group: "batch", Version: "v1beta1", Kind: "CronJob"}
		case *corev1.Service:
			gvks = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Service"}
		case *corev1.ConfigMap:
			gvks = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ConfigMap"}
		case *corev1.ServiceAccount:
			gvks = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ServiceAccount"}
		case *rbacv1.Role:
			gvks = schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "Role"}
		case *rbacv1.RoleBinding:
			gvks = schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "RoleBinding"}
		case *rbacv1.ClusterRole:
			gvks = schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRole"}
		case *rbacv1.ClusterRoleBinding:
			gvks = schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRoleBinding"}
		case *corev1.PersistentVolumeClaim:
			gvks = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "PersistentVolumeClaim"}
		case *corev1.PersistentVolume:
			gvks = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "PersistentVolume"}
		case *corev1.Secret:
			gvks = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Secret"}
		default:
			// 留空也行
		}
	}
	if gvks.Version != "" {
		if gvks.Group == "" {
			m["apiVersion"] = gvks.Version
		} else {
			m["apiVersion"] = gvks.Group + "/" + gvks.Version
		}
	}
	if gvks.Kind != "" {
		m["kind"] = gvks.Kind
	}
	return m
}

// ObjToMap 将Kubernetes对象转换为map[string]any
func ObjToMap(obj runtime.Object) (map[string]any, error) {
	j, err := json.Marshal(obj)
	if err != nil {
		return nil, err
	}
	m := map[string]any{}
	if err := json.Unmarshal(j, &m); err != nil {
		return nil, err
	}
	return m, nil
}

// getNodeByPath 在 data 中定位 parts 路径对应的节点并返回该节点；
// 如果路径穿过数组，会返回 []interface{}（包含所有非空的匹配子节点）
func getNodeByPath(data interface{}, parts []string, index int) interface{} {
	if index >= len(parts) {
		return data
	}

	switch d := data.(type) {
	case map[string]interface{}:
		val, ok := d[parts[index]]
		if !ok {
			return nil
		}
		return getNodeByPath(val, parts, index+1)

	case []interface{}:
		out := make([]interface{}, 0, len(d))
		for _, item := range d {
			if node := getNodeByPath(item, parts, index); node != nil {
				out = append(out, node)
			}
		}
		if len(out) == 0 {
			return nil
		}
		return out

	default:
		return nil
	}
}

// pruneNodeChildren 在 node 处只保留 allowed 中列出的子 key；
// node 可以是 map[string]interface{} 或 []interface{}（逐个元素裁剪）
func pruneNodeChildren(node interface{}, allowed map[string]bool) {
	switch n := node.(type) {
	case map[string]interface{}:
		for k := range n {
			if !allowed[k] {
				delete(n, k)
			}
		}
	case []interface{}:
		for _, item := range n {
			// 只对每个元素是 map 的情况做裁剪
			if m, ok := item.(map[string]interface{}); ok {
				pruneNodeChildren(m, allowed)
			}
		}
	default:
		// 非 map/非 slice，无法裁剪，直接忽略
	}
}

// ApplyExcludeRules 应用黑名单规则，移除指定的字段
// 但会保留白名单中明确指定的字段
func ApplyExcludeRules(data map[string]interface{}, excludes []string, includes []string) map[string]interface{} {
	// 创建数据的深拷贝，避免修改原始数据
	result := DeepCopyMap(data)

	// 构建白名单路径集合，用于快速检查
	includeSet := make(map[string]bool)
	for _, path := range includes {
		includeSet[path] = true
	}

	for _, excludePath := range excludes {
		// 如果路径在白名单中，则跳过不删除
		if includeSet[excludePath] {
			continue
		}

		// 按路径分割字段
		parts := strings.Split(excludePath, "/")
		if len(parts) == 0 {
			continue
		}

		// 从结果map中删除指定路径的值
		DeleteValueByPath(result, parts, 0)
	}
	if len(includeSet) > 0 {
		// 构建父路径 -> 允许的子字段集合
		parentAllowed := make(map[string]map[string]bool)
		for _, inc := range includes {
			parts := strings.Split(inc, "/")
			if len(parts) == 0 {
				continue
			}
			// 父路径为 parts[:len-1]，如果只有一个部分则父路径为空字符串表示根
			var parent string
			var child string
			if len(parts) == 1 {
				parent = ""
				child = parts[0]
			} else {
				parent = strings.Join(parts[:len(parts)-1], "/")
				child = parts[len(parts)-1]
			}
			if _, ok := parentAllowed[parent]; !ok {
				parentAllowed[parent] = make(map[string]bool)
			}
			parentAllowed[parent][child] = true
		}

		// 对每个父路径执行裁剪：在该父路径节点只保留 allowed 中列出的子 key
		for parentPath, allowed := range parentAllowed {
			if parentPath == "" {
				// 根节点特殊处理：只保留顶层被允许的 key
				for k := range result {
					if !allowed[k] {
						delete(result, k)
					}
				}
				continue
			}

			parts := strings.Split(parentPath, "/")
			node := getNodeByPath(result, parts, 0)
			if node == nil {
				continue
			}
			// node 可能是 map[string]interface{} 或 []interface{}（数组时逐个元素裁剪）
			pruneNodeChildren(node, allowed)
		}
	}
	return result
}

// ApplyRules 应用包含和排除规则到map
// 正确逻辑：先保留所有字段，移除黑名单字段，但白名单字段始终保留
func ApplyRules(data map[string]interface{}, rule *rules.FieldRule) map[string]interface{} {
	if rule == nil || (rule.Exclude == nil && rule.Include == nil) {
		return data
	}
	// 先复制所有数据
	result := DeepCopyMap(data)
	// 判断包含规则是否有效（非nil且有元素）
	includeValid := rule.Include != nil && len(rule.Include) > 0
	// 判断排除规则是否有效（非nil且有元素）
	excludeValid := rule.Exclude != nil && len(rule.Exclude) > 0
	switch {
	case excludeValid && !includeValid:
		//logger.L().Debug("仅应用排除规则")
		// 仅应用排除规则（黑名单）：排除指定字段，保留其他所有字段
		result = ApplyExcludeRules(result, rule.Exclude, rule.Include)

	case includeValid && !excludeValid:
		//logger.L().Debug("仅应用包含规则")
		// 仅应用包含规则（白名单）：只保留指定字段，删除其他所有字段
		// 先清空结果，再添加白名单字段（确保只保留白名单内容）
		result = make(map[string]interface{})
		ApplyIncludeRules(data, result, rule.Include)

	case includeValid && excludeValid:
		//logger.L().Debug("黑白名单都存在，需要综合处理")
		// 同时应用两种规则：先排除，再确保白名单字段被保留（白名单优先级更高）
		result = ApplyExcludeRules(result, rule.Exclude, rule.Include)

	default:
		// 无任何有效规则：返回原始数据
		return result
	}

	return result
}

// ApplyIncludeRules 应用白名单规则，确保指定的字段被保留
// 会从原始数据中提取这些字段并添加到结果中
func ApplyIncludeRules(data map[string]interface{}, result map[string]interface{}, includes []string) {
	for _, includePath := range includes {
		parts := strings.Split(includePath, "/")
		if len(parts) == 0 {
			continue
		}
		// GetValueByPath 返回以 parts[0] 为根的子树（map 或 nil）
		sub := GetValueByPath(data, parts, 0)
		if sub == nil {
			continue
		}
		// 将子树合并到 result（递归合并，数组按索引合并 map）
		if sm, ok := sub.(map[string]interface{}); ok {
			mergeMapInto(result, sm)
		} else {
			// 非 map 情况作为兜底（一般不会走到）
			mergeValueIntoByPath(result, parts, 0, sub)
		}
	}
}

// GetValueByPath 递归获取指定路径的值
func GetValueByPath(data interface{}, parts []string, index int) interface{} {
	if index >= len(parts) {
		// 到末尾，返回当前节点（可能是标量、map、slice）
		return data
	}

	current := parts[index]

	// 如果当前节点是 map，取当前 key 并继续构建子树
	if m, ok := data.(map[string]interface{}); ok {
		val, exists := m[current]
		if !exists {
			return nil
		}
		child := GetValueByPath(val, parts, index+1)
		if child == nil {
			return nil
		}
		// 返回一层 map 以保留树形结构
		return map[string]interface{}{current: child}
	}

	// 如果当前节点是数组（常见于 containers），则对每个元素分别提取子树，
	// 返回一个数组（每个元素通常是 map[string]interface{}，例如 {"env": [...]})
	if arr, ok := data.([]interface{}); ok {
		out := make([]interface{}, 0, len(arr))
		for _, item := range arr {
			// 注意：传入的 index 不变（因为 parts[index] 对每个数组元素都是同一个 key）
			child := GetValueByPath(item, parts, index)
			if child == nil {
				continue
			}
			// child 一般是 map[string]interface{}（例如 {"env": [...] }）
			if cm, ok := child.(map[string]interface{}); ok {
				out = append(out, cm)
			} else {
				// 万一不是 map，包一层避免扁平化
				out = append(out, map[string]interface{}{parts[index]: child})
			}
		}
		if len(out) == 0 {
			return nil
		}
		return out
	}

	// 无法继续解析，返回nil
	return nil
}

// DeleteValueByPath 递归删除指定路径的值
func DeleteValueByPath(data map[string]interface{}, parts []string, index int) {
	if index >= len(parts) {
		return
	}

	currentPart := parts[index]

	// 如果是最后一个部分，直接删除
	if index == len(parts)-1 {
		delete(data, currentPart)
		return
	}

	// 检查当前部分是否存在
	if val, exists := data[currentPart]; exists {
		// 处理嵌套map
		if nestedMap, ok := val.(map[string]interface{}); ok {
			DeleteValueByPath(nestedMap, parts, index+1)
			// 如果删除后map为空，也一并删除
			if len(nestedMap) == 0 {
				delete(data, currentPart)
			}
			return
		}

		// 处理数组
		if arr, ok := val.([]interface{}); ok {
			for i := range arr {
				if nestedMap, ok := arr[i].(map[string]interface{}); ok {
					DeleteValueByPath(nestedMap, parts, index+1)
				}
			}
		}

		// 处理数组中的特定元素
		if strings.HasPrefix(currentPart, "[") && strings.HasSuffix(currentPart, "]") {
			if arr, ok := val.([]interface{}); ok {
				for i := range arr {
					if nestedMap, ok := arr[i].(map[string]interface{}); ok {
						DeleteValueByPath(nestedMap, parts, index+1)
					}
				}
			}
		}
	}
}

// DeepCopyMap 深拷贝map，避免修改原始数据
func DeepCopyMap(data map[string]interface{}) map[string]interface{} {
	result := make(map[string]interface{})
	for k, v := range data {
		switch val := v.(type) {
		case map[string]interface{}:
			result[k] = DeepCopyMap(val)
		case []interface{}:
			copiedSlice := make([]interface{}, len(val))
			for i, item := range val {
				if m, ok := item.(map[string]interface{}); ok {
					copiedSlice[i] = DeepCopyMap(m)
				} else {
					copiedSlice[i] = item
				}
			}
			result[k] = copiedSlice
		default:
			result[k] = val
		}
	}
	return result
}

/* ----------------- 辅助合并函数 ----------------- */

// 将 src 的内容递归合并到 dst 中（dst 被修改）
func mergeMapInto(dst map[string]interface{}, src map[string]interface{}) {
	for k, v := range src {
		if existing, ok := dst[k]; ok {
			dst[k] = mergeValues(existing, v)
		} else {
			// 直接拷贝（不做深拷贝，若需要可改为深拷贝）
			dst[k] = v
		}
	}
}

// 合并两个任意类型的值，返回合并后的值（不修改原来 a/b 的结构）
func mergeValues(a, b interface{}) interface{} {
	// map + map => 递归合并
	am, aok := a.(map[string]interface{})
	bm, bok := b.(map[string]interface{})
	if aok && bok {
		// 合并到 a 的副本（为安全起见，这里直接修改 a 若你不想改变 a，可以先复制）
		for k, v := range bm {
			if ev, exists := am[k]; exists {
				am[k] = mergeValues(ev, v)
			} else {
				am[k] = v
			}
		}
		return am
	}

	// slice + slice => 按索引合并
	aslice, aok2 := a.([]interface{})
	bslice, bok2 := b.([]interface{})
	if aok2 && bok2 {
		return mergeArrayByIndex(aslice, bslice)
	}

	// 其中一个是 map，另一个是 slice 或标量：prefers b（后者覆盖前者）
	return b
}

// 按索引合并两个数组（数组元素若为 map 会合并 map；否则后者覆盖前者）
func mergeArrayByIndex(a, b []interface{}) []interface{} {
	max1 := len(a)
	if len(b) > max1 {
		max1 = len(b)
	}
	out := make([]interface{}, max1)
	for i := 0; i < max1; i++ {
		var av, bv interface{}
		if i < len(a) {
			av = a[i]
		}
		if i < len(b) {
			bv = b[i]
		}
		if av == nil {
			out[i] = bv
			continue
		}
		if bv == nil {
			out[i] = av
			continue
		}
		// 都存在，合并
		out[i] = mergeValues(av, bv)
	}
	return out
}

// 兜底：把 value 放到 data 的 parts 路径下（按需调用）
// （在本实现中不常用，主要用于非 map/非 slice 的情况）
func mergeValueIntoByPath(data map[string]interface{}, parts []string, index int, value interface{}) {
	cur := data
	for i := index; i < len(parts)-1; i++ {
		k := parts[i]
		if _, exists := cur[k]; !exists {
			cur[k] = make(map[string]interface{})
		}
		if nextMap, ok := cur[k].(map[string]interface{}); ok {
			cur = nextMap
		} else {
			newM := make(map[string]interface{})
			cur[k] = newM
			cur = newM
		}
	}
	cur[parts[len(parts)-1]] = value
}
